import numpy as np
import numhelp
import pautaCriterion2
import statistics
import matplotlib.pyplot as plt

data=np.zeros((1000,2)) # 在此存储表中读到的用户属性数据
data=pautaCriterion2.GetGoodList(data) # 拉依达准则剔除不可信数据
_k1=0 # 预定限额
_k2=1 # 预定时间
_x=2 # 用户位置x
_y=3 # 用户位置y
memberNum,dim = data.shape # 有如上四种属性，dim值为4

# 规范化预定时间（原先为与6:30的差值）
for i in range(memberNum):
    time=data[i, _k2]
    if time==0:
        data[i, _k2]= 1 / 2
    else:
        data[i, _k2]= 1 / time # 时间越早越好（值越大）

dataNor=numhelp.normalization(data) # 归一化
dataLamda=statistics.entropy(dataNor) # 熵权法计算各个维度权值

# 计算各个会员任务完成能力值
cp=np.zeros(memberNum)
for i in range(memberNum):
    cp[i]= dataLamda[_k1] * dataNor[i, _k1] + dataLamda[_k2] * dataNor[i, _k2]

# 地块结构
class block:
    def __init__(self,cp):
        self.cp=cp
        self.memberList=[]
        self.taskNum=0
    def addMember(self,member):
        self.memberList.append(member) # 放的是下标
    def addTask(self): # 论文中不涉及任务属性（如任务标价）与未完成度的相关性，因此只计算任务数即可（不过任务标价这个真的不太好说）
        self.taskNum+=1
    def inReg(self,x,y):
        pass # 计算是否在区域内，略
    # 后期计算
    def caluMemberNum(self):
        self.memberNum=len(self.memberList)
    def caluAvgCp(self):
        self.avgCp=0
        for i in self.memberList:
            self.avgCp+=self.cp[i]
        self.avgCp/=self.memberNum

allBlock=[] # 在此创建所有地块对象，用cp初始化

# 将用户数据装载到地块
for i in range(memberNum):
    for b in allBlock:
        if b.inReg(data[i, _x], data[i, _y]):
            b.addMember(i)

# 将任务数据装载到地块
taskData=np.zeros((1000,3)) # 在此存储表中读到的任务属性
_x=0 # 经度
_y=1 # 纬度
_isFinish=2 # 该任务是否完成
# 后面聚类等等只用经纬度，所以先把任务是否完成这个属性提取出来
taskIsFinishList=taskData[:,_isFinish]
taskData=np.delete(taskData, _isFinish, axis=1) # 把isFinish属性从taskData里删除
taskNum,dim=taskData.shape

# 建立任务到地块的映射，并对地块中任务计数
blockMap=np.zeros(taskNum)
for i in range(taskNum):
    for b in allBlock:
        if b.inReg(taskData[i, _x], taskData[i, _y]):
            b.addTask()
            blockMap[i]=b

# 所有装载的数据计算完成
for b in allBlock:
    b.caluMemberNum()
    b.caluAvgCp()

# 对任务位置聚类
centerList,labelsList=statistics.kmean(taskData,3)

def showKMeanResult(X,label_pred): # 调用这个可以显示聚类结果，这里先不显示了
    x0 = X[label_pred == 0]
    x1 = X[label_pred == 1]
    x2 = X[label_pred == 2]
    plt.scatter(x0[:, 0], x0[:, 1], c="red", marker='o', label='label0')
    plt.scatter(x1[:, 0], x1[:, 1], c="green", marker='*', label='label1')
    plt.scatter(x2[:, 0], x2[:, 1], c="blue", marker='+', label='label2')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend(loc=2)
    plt.show()

def caluDistance(sub,pointList,labelsList,centerList): # 计算与聚类中心距离
    label=labelsList[sub] # 是第几类
    center=centerList[label]
    point=[pointList[sub, _x], pointList[sub, _y]]
    return ((point[_x] - center[_x]) ^ 2) - ((point[_y] - center[_y]) ^ 2)

# 计算所有任务与其聚类中心距离
distList=np.zeros(taskNum)
for i in range(taskNum):
    distList[i]=caluDistance(i,taskData,labelsList,centerList)

# 目前统计出四个指标：地块内任务数，地块内会员数，地块内会员平均能力值，任务距中心点距离
# 下面建立一个以任务为主体的表，包含以上四个属性（前三个为任务所属地块确定）
assoMat=np.zeros((taskNum,5)) # 最后一个维度是是否完成，即关联度计算的关联对象
_memberNum=1
_avgcp=2
_taskdist=3
_taskNum=4
_isFinish=0 # 灰色关联度分析标准列要放在第一位
assoMat[:,_taskdist]=distList # 把任务到中心点距离安排上
assoMat[:,_isFinish]=taskIsFinishList # 把是否完成安排上
for i in range(taskNum): # 其它的安排上
    nowblock=blockMap[i]
    assoMat[i,_taskNum]=nowblock.taskNum
    assoMat[i,_memberNum]=nowblock.memberNum
    assoMat[i,_avgcp]=nowblock.avgCp

# 灰色关联度分析
assoMat=statistics.normalization(assoMat)
result=statistics.gra(assoMat)
_memberNum=0
_avgcp=1
_taskdist=2
_taskNum=3